/*!
 * \file WtDataWriter.h
 * \project	WonderTrader
 *
 * \author Wesley
 * \date 2020/03/30
 * 
 * \brief WonderTrader数据写入器头文件
 * 
 * \details 该文件定义了WtDataWriter数据写入器类，是WonderTrader数据存储系统的核心写入组件：
 *          - 实现IDataWriter接口，提供统一的数据写入服务
 *          - 支持实时数据的高效写入和缓存管理
 *          - 支持多种数据类型：K线、Tick、成交明细、委托明细、委托队列
 *          - 使用内存映射文件技术提高数据写入效率
 *          - 支持异步数据处理和任务队列机制
 *          - 支持数据压缩和历史数据转储
 *          - 提供线程安全的并发写入支持
 */
#pragma once
#include "DataDefine.h"

#include "../Includes/FasterDefs.h"
#include "../Includes/IDataWriter.h"
#include "../Share/StdUtils.hpp"
#include "../Share/BoostMappingFile.hpp"
#include "../Share/SpinMutex.hpp"

#include <queue>
#include <map>

typedef std::shared_ptr<BoostMappingFile> BoostMFPtr; ///< 内存映射文件智能指针类型定义

NS_WTP_BEGIN
class WTSContractInfo;
NS_WTP_END

USING_NS_WTP;

/*!
 * \class WtDataWriter
 * \brief WonderTrader数据写入器类
 * 
 * \details 数据写入器是WonderTrader数据存储系统的核心写入组件，主要功能包括：
 *          - 实时数据写入：支持Tick、Level2、K线数据的实时写入
 *          - 缓存管理：使用内存映射文件和缓存机制提高写入效率
 *          - 异步处理：支持异步数据处理和任务队列，避免阻塞主线程
 *          - 数据转储：支持历史数据的定期转储和压缩存储
 *          - 线程安全：使用自旋锁等机制保证多线程环境下的数据一致性
 *          - 格式支持：支持多种K线周期和Level2数据格式
 *          - 配置灵活：支持选择性禁用某些数据类型的写入
 */
class WtDataWriter : public IDataWriter
{
public:
	/*!
	 * \brief 构造函数
	 * 
	 * 初始化数据写入器，设置默认参数
	 */
	WtDataWriter();
	
	/*!
	 * \brief 析构函数
	 * 
	 * 清理资源，关闭文件映射和线程
	 */
	~WtDataWriter();	

private:
	/*!
	 * \brief 调整实时数据块大小的模板函数
	 * \tparam HeaderType 数据块头部类型
	 * \tparam T 数据项类型
	 * \param mfPtr 内存映射文件智能指针引用
	 * \param nCount 数据项数量
	 * \return 调整后的数据块指针
	 * 
	 * 当数据块容量不足时，自动扩展数据块大小
	 */
	template<typename HeaderType, typename T>
	void* resizeRTBlock(BoostMFPtr& mfPtr, uint32_t nCount);

	/*!
	 * \brief 数据处理循环函数
	 * 
	 * 后台线程的主循环，处理异步数据任务队列
	 */
	void  proc_loop();

	/*!
	 * \brief 数据检查循环函数
	 * 
	 * 后台线程的检查循环，定期检查和维护数据状态
	 */
	void  check_loop();

	/*!
	 * \brief 将K线数据转储到文件
	 * \param ct 合约信息指针
	 * \return 转储的数据条数
	 * 
	 * 将内存中的K线数据转储到磁盘文件
	 */
	uint32_t  dump_bars_to_file(WTSContractInfo* ct);

	/*!
	 * \brief 通过外部转储器转储K线数据
	 * \param ct 合约信息指针
	 * \return 转储的数据条数
	 * 
	 * 使用外部数据转储器转储K线数据
	 */
	uint32_t  dump_bars_via_dumper(WTSContractInfo* ct);

private:
	/*!
	 * \brief 转储日线数据
	 * \param ct 合约信息指针
	 * \param newBar 新的K线数据指针
	 * \return 是否转储成功
	 * 
	 * 处理日线数据的转储逻辑
	 */
	bool	dump_day_data(WTSContractInfo* ct, WTSBarStruct* newBar);

	/*!
	 * \brief 处理数据块的压缩和格式转换
	 * \param tag 数据标签
	 * \param content 数据内容引用
	 * \param isBar 是否为K线数据
	 * \param bKeepHead 是否保留数据块头部，默认为true
	 * \return 处理是否成功
	 * 
	 * 处理数据块的压缩、版本兼容性和格式转换
	 */
	bool	proc_block_data(const char* tag, std::string& content, bool isBar, bool bKeepHead = true);

public:
	/*!
	 * \brief 初始化数据写入器
	 * \param params 配置参数
	 * \param sink 数据写入器回调接口
	 * \return 是否初始化成功
	 * 
	 * 使用配置参数初始化数据写入器，设置数据目录、缓存参数等
	 */
	virtual bool init(WTSVariant* params, IDataWriterSink* sink) override;
	
	/*!
	 * \brief 释放资源
	 * 
	 * 停止后台线程，关闭文件映射，清理所有资源
	 */
	virtual void release() override;

	/*!
	 * \brief 写入Tick数据
	 * \param curTick 当前Tick数据指针
	 * \param procFlag 处理标志
	 * \return 是否写入成功
	 * 
	 * 将Tick数据写入到实时数据块和历史数据文件
	 */
	virtual bool writeTick(WTSTickData* curTick, uint32_t procFlag) override;

	/*!
	 * \brief 写入委托队列数据
	 * \param curOrdQue 当前委托队列数据指针
	 * \return 是否写入成功
	 * 
	 * 将Level2委托队列数据写入到数据块
	 */
	virtual bool writeOrderQueue(WTSOrdQueData* curOrdQue) override;

	/*!
	 * \brief 写入委托明细数据
	 * \param curOrdDetail 当前委托明细数据指针
	 * \return 是否写入成功
	 * 
	 * 将Level2委托明细数据写入到数据块
	 */
	virtual bool writeOrderDetail(WTSOrdDtlData* curOrdDetail) override;

	/*!
	 * \brief 写入成交数据
	 * \param curTrans 当前成交数据指针
	 * \return 是否写入成功
	 * 
	 * 将Level2逐笔成交数据写入到数据块
	 */
	virtual bool writeTransaction(WTSTransData* curTrans) override;

	/*!
	 * \brief 转储历史数据
	 * \param sid 交易时段ID
	 * 
	 * 在交易时段结束后转储历史数据
	 */
	virtual void transHisData(const char* sid) override;
	
	/*!
	 * \brief 检查交易时段是否已处理
	 * \param sid 交易时段ID
	 * \return 是否已处理
	 * 
	 * 检查指定交易时段的数据是否已经处理完毕
	 */
	virtual bool isSessionProceeded(const char* sid) override;

	/*!
	 * \brief 获取当前Tick数据
	 * \param code 合约代码
	 * \param exchg 交易所代码，默认为空
	 * \return 当前Tick数据指针
	 * 
	 * 从缓存中获取指定合约的最新Tick数据
	 */
	virtual WTSTickData* getCurTick(const char* code, const char* exchg = "") override;

private:
	IBaseDataMgr*		_bd_mgr;	///< 基础数据管理器指针

	/*!
	 * \struct KBlockPair
	 * \brief K线数据块配对结构体
	 * 
	 * \details 用于管理K线数据块的结构体，包含：
	 *          - 数据块指针：指向实际的K线数据块
	 *          - 文件映射：内存映射文件的智能指针
	 *          - 互斥锁：保证线程安全的自旋锁
	 *          - 时间戳：最后更新时间
	 */
	typedef struct _KBlockPair
	{
		RTKlineBlock*	_block;		///< K线数据块指针
		BoostMFPtr		_file;		///< 内存映射文件智能指针
		SpinMutex		_mutex;		///< 自旋锁，保证线程安全
		uint64_t		_lasttime;	///< 最后更新时间

		/*!
		 * \brief 构造函数
		 * 
		 * 初始化所有成员为默认值
		 */
		_KBlockPair()
		{
			_block = NULL;
			_file = NULL;
			_lasttime = 0;
		}

	} KBlockPair;
	typedef faster_hashmap<LongKey, KBlockPair*>	KBlockFilesMap; ///< K线数据块映射表

	/*!
	 * \struct TickBlockPair
	 * \brief Tick数据块配对结构体
	 * 
	 * \details 用于管理Tick数据块的结构体，包含：
	 *          - 数据块指针：指向实际的Tick数据块
	 *          - 文件映射：内存映射文件的智能指针
	 *          - 互斥锁：保证线程安全的自旋锁
	 *          - 时间戳：最后更新时间
	 *          - 文件流：用于数据写入的文件流
	 */
	typedef struct _TickBlockPair
	{
		RTTickBlock*	_block;		///< Tick数据块指针
		BoostMFPtr		_file;		///< 内存映射文件智能指针
		SpinMutex		_mutex;		///< 自旋锁，保证线程安全
		uint64_t		_lasttime;	///< 最后更新时间

		std::shared_ptr< std::ofstream>	_fstream;	///< 文件输出流智能指针

		/*!
		 * \brief 构造函数
		 * 
		 * 初始化所有成员为默认值
		 */
		_TickBlockPair()
		{
			_block = NULL;
			_file = NULL;
			_fstream = NULL;
			_lasttime = 0;
		}
	} TickBlockPair;
	typedef faster_hashmap<LongKey, TickBlockPair*>	TickBlockFilesMap; ///< Tick数据块映射表

	/*!
	 * \struct TransBlockPair
	 * \brief 逐笔成交数据块配对结构体
	 * 
	 * \details 用于管理逐笔成交数据块的结构体，包含：
	 *          - 数据块指针：指向实际的成交数据块
	 *          - 文件映射：内存映射文件的智能指针
	 *          - 互斥锁：保证线程安全的自旋锁
	 *          - 时间戳：最后更新时间
	 */
	typedef struct _TransBlockPair
	{
		RTTransBlock*	_block;		///< 成交数据块指针
		BoostMFPtr		_file;		///< 内存映射文件智能指针
		SpinMutex		_mutex;		///< 自旋锁，保证线程安全
		uint64_t		_lasttime;	///< 最后更新时间

		/*!
		 * \brief 构造函数
		 * 
		 * 初始化所有成员为默认值
		 */
		_TransBlockPair()
		{
			_block = NULL;
			_file = NULL;
			_lasttime = 0;
		}
	} TransBlockPair;
	typedef faster_hashmap<LongKey, TransBlockPair*>	TransBlockFilesMap; ///< 成交数据块映射表

	/*!
	 * \struct OrdDtlBlockPair
	 * \brief 逐笔委托数据块配对结构体
	 * 
	 * \details 用于管理逐笔委托数据块的结构体，包含：
	 *          - 数据块指针：指向实际的委托明细数据块
	 *          - 文件映射：内存映射文件的智能指针
	 *          - 互斥锁：保证线程安全的自旋锁
	 *          - 时间戳：最后更新时间
	 */
	typedef struct _OdeDtlBlockPair
	{
		RTOrdDtlBlock*	_block;		///< 委托明细数据块指针
		BoostMFPtr		_file;		///< 内存映射文件智能指针
		SpinMutex		_mutex;		///< 自旋锁，保证线程安全
		uint64_t		_lasttime;	///< 最后更新时间

		/*!
		 * \brief 构造函数
		 * 
		 * 初始化所有成员为默认值
		 */
		_OdeDtlBlockPair()
		{
			_block = NULL;
			_file = NULL;
			_lasttime = 0;
		}
	} OrdDtlBlockPair;
	typedef faster_hashmap<LongKey, OrdDtlBlockPair*>	OrdDtlBlockFilesMap; ///< 委托明细数据块映射表

	/*!
	 * \struct OrdQueBlockPair
	 * \brief 委托队列数据块配对结构体
	 * 
	 * \details 用于管理委托队列数据块的结构体，包含：
	 *          - 数据块指针：指向实际的委托队列数据块
	 *          - 文件映射：内存映射文件的智能指针
	 *          - 互斥锁：保证线程安全的自旋锁
	 *          - 时间戳：最后更新时间
	 */
	typedef struct _OdeQueBlockPair
	{
		RTOrdQueBlock*	_block;		///< 委托队列数据块指针
		BoostMFPtr		_file;		///< 内存映射文件智能指针
		SpinMutex		_mutex;		///< 自旋锁，保证线程安全
		uint64_t		_lasttime;	///< 最后更新时间

		/*!
		 * \brief 构造函数
		 * 
		 * 初始化所有成员为默认值
		 */
		_OdeQueBlockPair()
		{
			_block = NULL;
			_file = NULL;
			_lasttime = 0;
		}
	} OrdQueBlockPair;
	typedef faster_hashmap<LongKey, OrdQueBlockPair*>	OrdQueBlockFilesMap; ///< 委托队列数据块映射表
	

	KBlockFilesMap	_rt_min1_blocks;	///< 实时1分钟K线数据块映射表
	KBlockFilesMap	_rt_min5_blocks;	///< 实时5分钟K线数据块映射表

	TickBlockFilesMap	_rt_ticks_blocks;	///< 实时Tick数据块映射表
	TransBlockFilesMap	_rt_trans_blocks;	///< 实时成交数据块映射表
	OrdDtlBlockFilesMap _rt_orddtl_blocks;	///< 实时委托明细数据块映射表
	OrdQueBlockFilesMap _rt_ordque_blocks;	///< 实时委托队列数据块映射表

	SpinMutex		_lck_tick_cache;		///< Tick缓存自旋锁
	faster_hashmap<LongKey, uint32_t> _tick_cache_idx;	///< Tick缓存索引映射表
	BoostMFPtr		_tick_cache_file;		///< Tick缓存文件映射指针
	RTTickCache*	_tick_cache_block;		///< Tick缓存数据块指针

	typedef std::function<void()> TaskInfo;	///< 任务信息类型定义
	std::queue<TaskInfo>	_tasks;			///< 任务队列
	StdThreadPtr			_task_thrd;		///< 任务处理线程
	StdUniqueMutex			_task_mtx;		///< 任务队列互斥锁
	StdCondVariable			_task_cond;		///< 任务队列条件变量

	std::string		_base_dir;			///< 基础数据目录路径
	std::string		_cache_file;		///< 缓存文件路径
	uint32_t		_log_group_size;	///< 日志组大小
	bool			_async_proc;		///< 是否异步处理

	StdCondVariable	_proc_cond;			///< 处理条件变量
	StdUniqueMutex	_proc_mtx;			///< 处理互斥锁
	std::queue<std::string> _proc_que;	///< 处理队列
	StdThreadPtr	_proc_thrd;			///< 处理线程
	StdThreadPtr	_proc_chk;			///< 检查线程
	bool			_terminated;		///< 是否已终止

	bool			_save_tick_log;		///< 是否保存Tick日志

	bool			_disable_tick;		///< 是否禁用Tick数据写入
	bool			_disable_min1;		///< 是否禁用1分钟K线写入
	bool			_disable_min5;		///< 是否禁用5分钟K线写入
	bool			_disable_day;		///< 是否禁用日线写入

	bool			_disable_trans;		///< 是否禁用成交数据写入
	bool			_disable_ordque;	///< 是否禁用委托队列写入
	bool			_disable_orddtl;	///< 是否禁用委托明细写入
	
	std::map<std::string, uint32_t> _proc_date;	///< 处理日期映射表

private:
	/*!
	 * \brief 加载缓存数据
	 * 
	 * 从缓存文件加载已有的Tick缓存数据
	 */
	void loadCache();

	/*!
	 * \brief 更新缓存数据
	 * \param ct 合约信息指针
	 * \param curTick 当前Tick数据指针
	 * \param procFlag 处理标志
	 * \return 是否更新成功
	 * 
	 * 更新Tick缓存中的最新数据
	 */
	bool updateCache(WTSContractInfo* ct, WTSTickData* curTick, uint32_t procFlag);

	/*!
	 * \brief 将Tick数据写入到Tick数据块
	 * \param ct 合约信息指针
	 * \param curTick 当前Tick数据指针
	 * 
	 * 将Tick数据写入到对应的实时Tick数据块
	 */
	void pipeToTicks(WTSContractInfo* ct, WTSTickData* curTick);

	/*!
	 * \brief 将Tick数据转换为K线数据
	 * \param ct 合约信息指针
	 * \param curTick 当前Tick数据指针
	 * 
	 * 根据Tick数据更新对应的K线数据块（1分钟、5分钟、日线）
	 */
	void pipeToKlines(WTSContractInfo* ct, WTSTickData* curTick);

	/*!
	 * \brief 获取K线数据块
	 * \param ct 合约信息指针
	 * \param period K线周期
	 * \param bAutoCreate 是否自动创建，默认为true
	 * \return K线数据块配对指针
	 * 
	 * 根据合约和周期获取对应的K线数据块，如不存在可选择自动创建
	 */
	KBlockPair* getKlineBlock(WTSContractInfo* ct, WTSKlinePeriod period, bool bAutoCreate = true);

	/*!
	 * \brief 获取Tick数据块
	 * \param ct 合约信息指针
	 * \param curDate 当前日期
	 * \param bAutoCreate 是否自动创建，默认为true
	 * \return Tick数据块配对指针
	 * 
	 * 根据合约和日期获取对应的Tick数据块，如不存在可选择自动创建
	 */
	TickBlockPair* getTickBlock(WTSContractInfo* ct, uint32_t curDate, bool bAutoCreate = true);
	
	/*!
	 * \brief 获取成交数据块
	 * \param ct 合约信息指针
	 * \param curDate 当前日期
	 * \param bAutoCreate 是否自动创建，默认为true
	 * \return 成交数据块配对指针
	 * 
	 * 根据合约和日期获取对应的成交数据块，如不存在可选择自动创建
	 */
	TransBlockPair* getTransBlock(WTSContractInfo* ct, uint32_t curDate, bool bAutoCreate = true);
	
	/*!
	 * \brief 获取委托明细数据块
	 * \param ct 合约信息指针
	 * \param curDate 当前日期
	 * \param bAutoCreate 是否自动创建，默认为true
	 * \return 委托明细数据块配对指针
	 * 
	 * 根据合约和日期获取对应的委托明细数据块，如不存在可选择自动创建
	 */
	OrdDtlBlockPair* getOrdDtlBlock(WTSContractInfo* ct, uint32_t curDate, bool bAutoCreate = true);
	
	/*!
	 * \brief 获取委托队列数据块
	 * \param ct 合约信息指针
	 * \param curDate 当前日期
	 * \param bAutoCreate 是否自动创建，默认为true
	 * \return 委托队列数据块配对指针
	 * 
	 * 根据合约和日期获取对应的委托队列数据块，如不存在可选择自动创建
	 */
	OrdQueBlockPair* getOrdQueBlock(WTSContractInfo* ct, uint32_t curDate, bool bAutoCreate = true);

	/*!
	 * \brief 释放数据块的模板函数
	 * \tparam T 数据块类型
	 * \param block 数据块指针
	 * 
	 * 释放指定类型的数据块资源
	 */
	template<typename T>
	void	releaseBlock(T* block);

	/*!
	 * \brief 推送任务到任务队列
	 * \param task 任务信息
	 * 
	 * 将任务推送到异步处理队列中，由后台线程处理
	 */
	void pushTask(TaskInfo task);
};

